package com.zk.algorithm.sort;

import com.zk.algorithm.Utils;

/**
 * O(nlogn)，构建一个最大堆，每次把堆中的顶部元素移至最后一个元素，这样从后往前依次排序
 *
 * 13,11,12,5,6,7
 * 7,11,12,5,6 | 13 => 12,11,7,5,6 | 13
 * 6,11,7,5 | 12,13 => 11,6,7,5 | 12,13
 * 5,6,7 | 11,12,13 => 7,6,5 | 11,12,13
 * 5,6 | 7,11,12,13 => 6,5 | 7,11,12,13
 * 5 | 6,7,11,12,13
 * 5,6,7,11,12,13
 */
public class HeapSort {

    public static void main(String...args) {
        int[] arr = new int[]{ 12, 11, 13, 5, 6, 7 };

        new HeapSort().sort(arr);

        Utils.println(arr);
    }

    public void sort(int arr[]) {
        int n = arr.length;

        // Build heap (rearrange array)
        for (int i = n / 2 - 1; i >= 0; i--) // 从无序数据中构造一个最大堆 [n/2-1 → 0]
            // 对的最大长度为 n
            heapify(arr, n, i);

        // One by one extract an element from heap
        for (int i = n - 1; i >= 0; i--) { // [n-1 → 0]
            // Move current root to end
            Utils.swap(arr, 0, i);

            // call max heapify on the reduced heap
            // 堆的最大长度递减 i: [n-1 → 0]
            // 即每次最后一个元素都不在堆中了其实
            heapify(arr, i, 0);
        }
    }

    // To heapify a subtree rooted with node i which is
    // an index in arr[]. n is size of heap
    void heapify(int arr[], int n, int root) {
        int largest = root;  // Initialize largest as root
        int left = 2 * root + 1;  // left = 2*i + 1
        int right = 2 * root + 2;  // right = 2*i + 2

        // ====================================
        // 如果 left/right > root，那么
        // root 和 left/right 中最大的那个进行交换
        // ====================================

        // If left child is larger than root
        if (left < n && arr[left] > arr[largest])
            largest = left;

        // If right child is larger than largest so far
        if (right < n && arr[right] > arr[largest])
            largest = right;

        // ====================================
        // 子树进行递归
        // ====================================

        // If largest is not root
        if (largest != root) {
            Utils.swap(arr, root, largest);

            // Recursively heapify the affected sub-tree
            heapify(arr, n, largest);
        }
    }

}
